package com.amoyt.project.service.visitor.impl;

import com.amoyt.project.config.redis.RedisCache;
import com.amoyt.project.config.redis.RedisIdWork;
import com.amoyt.project.constants.*;
import com.amoyt.project.domain.bo.LoginUser;
import com.amoyt.project.domain.dto.VisitorLoginDto;
import com.amoyt.project.domain.dto.update.VisitorUpdateDto;
import com.amoyt.project.domain.pojo.User;
import com.amoyt.project.domain.pojo.UserRole;
import com.amoyt.project.domain.res.Result;
import com.amoyt.project.domain.vo.LoginInfoVo;
import com.amoyt.project.mapper.UserMapper;
import com.amoyt.project.mapper.UserRoleMapper;
import com.amoyt.project.service.visitor.VisitorService;
import com.amoyt.project.utils.ConvertBeanUtils;
import com.amoyt.project.utils.JwtUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Date: 2025/8/10
 * @Time: 20:37
 * @Author: TQ_QT
 * @Description:
 */
@Service
@Slf4j
public class VisitorServiceImpl implements VisitorService {

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisIdWork redisIdWork;
    @Autowired
    private UserRoleMapper userRoleMapper;
    /**
     * 认证管理器
     */
    @Autowired
    private AuthenticationManager authenticationManager;
    /**
     * jwt工具类
     */
    @Autowired
    private JwtUtil jwtUtil;


    @Override
    public Result getPhoneCode(String phone) {

        //TODO 是否已注册
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone_number", phone);
        List<User> users = userMapper.selectList(queryWrapper);
        if (users.size() > 0){
            return Result.fail("该手机号已注册");
        }

        //生成
        String code = generateVerifyCode();

        //存入redis
        redisCache.setCacheObject(RedisConstants.REGISTER_CODE_KEY + phone, code,RedisConstants.REGISTER_CODE_KEY_PRE_TTL,TimeUnit.MINUTES);

        log.info("访客登录-发送验证码：{}", code);

        return Result.success("测试阶段，验证码："+code);
    }

    @Override
    @Transactional
    public Result register(VisitorLoginDto visitorLoginDto) {
        //注册就行
        String phone = visitorLoginDto.getPhone();
        String code = visitorLoginDto.getCode();
        String password = visitorLoginDto.getPassword();
        if (password == null || password.equals("")){
            password = InfoConstants.DEFAULT_PASSWORD;
            //TODO 或者返回错误信息
        }

        //1.设置默认密码
        password = new BCryptPasswordEncoder().encode(password);

        //2.用户id
        String userId = IdConstants.VISITOR_ID_PREFIX + redisIdWork.nextId(IdConstants.VISITOR_ID_PREFIX);
        User addUser = User.builder()
                .userId(userId)
                .userName(phone)
                .phoneNumber(phone)
                .password(password)
                .userType(UserTypeConstants.USER)
                .build();

        //角色连接
        UserRole userRole = UserRole.builder()
                .userId(userId)
                .roleId(7L)
                .build();

        userMapper.insert(addUser);
        userRoleMapper.insert(userRole);

        //删除redis
        redisCache.deleteObject(RedisConstants.CACHE_USER_DATA);

        return Result.success(ResponseConstants.SUCCESS_REGISTER);
    }

    @Override
    public Result verify(String phone, String code) {
        //获取redis
        String codeCache = (String) redisCache.getCacheObject(RedisConstants.REGISTER_CODE_KEY + phone);
        if (codeCache == null ){
            return Result.fail(ResponseConstants.VERIFY_CODE_NOT_EXIST);
        }
        if (!codeCache.equals(code)){
            return Result.fail(ResponseConstants.VERIFY_CODE_ERROR);
        }
        return Result.success(ResponseConstants.VERIFY_CODE_SUCCESS,null);
    }

    @Override
    public Result login(VisitorLoginDto visitorLoginDto) {
        //1.封装
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(visitorLoginDto.getUsername(), visitorLoginDto.getPassword());

        //2.认证
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        //判断结果
        if (Objects.isNull(authenticate)) {
            throw new RuntimeException("登录失败！");
        }
        //3.认证成功 （拿到认证通过后的登录用户对象）
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();

        //4.用户编号，生成jwt
        String userId = loginUser.getUser().getUserId().toString();
        String jwt = jwtUtil.createJWT(userId);

        //5.信息存入redis
        redisCache.setCacheObject(RedisConstants.LOGIN_USER_KEY_PRE + userId, loginUser, RedisConstants.LOGIN_VISITOR_TTL, TimeUnit.HOURS);

        //6.返回结果

        // 获取第一个权限并去除ROLE_前缀 处理可能的空集合和权限格式问题
        String permission = loginUser.getAuthorities().stream()
                // 获取第一个元素（如果集合为空会返回空Optional）
                .findFirst()
                // 处理权限字符串
                .map(authority -> {
                    String authStr = authority.getAuthority();
                    // 只有以ROLE_开头时才截取，否则返回原字符串
                    return authStr.startsWith("ROLE_") ? authStr.substring(5) : authStr;
                })
                // 当没有权限时，返回默认值或抛出异常
                .orElse(""); // 或者使用 orElseThrow() 抛出异常
        LoginInfoVo loginInfoVo = LoginInfoVo.builder()
                .token(jwt)
                .role(permission)
                .build();

        return Result.success(ResponseConstants.SUCCESS_LOGIN,loginInfoVo);
    }

    @Override
    public Result logout() {
        //干掉登录缓存
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String key = RedisConstants.LOGIN_USER_KEY_PRE + loginUser.getUser().getUserId();
        redisCache.deleteObject(key);
        return Result.success(ResponseConstants.SUCCESS_LOGOUT);
    }

    @Override
    public Result update(VisitorUpdateDto visitorUpdateDto) {
        //密码加密
        visitorUpdateDto.setPassword(new BCryptPasswordEncoder().encode(visitorUpdateDto.getPassword()));
        User user = ConvertBeanUtils.convert(visitorUpdateDto, User.class);
        return userMapper.updateById(user) > 0 ? Result.success(ResponseConstants.UPDATE_SUCCESS) : Result.fail(ResponseConstants.UPDATE_FAIL);
    }

    @Override
    public Result getOwnInfo() {
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        User user = userMapper.selectById(loginUser.getUser().getUserId());
        return Result.success(user);
    }

    /**
     * 随机生成6位数验证码数字+字母
     * @return
     */
    private String generateVerifyCode() {
        String data = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            int index = (int) (Math.random() * data.length());
            sb.append(data.charAt(index));
        }
        return sb.toString();
    }
}
